#ifndef OPPC_HPP
#define OPPC_HPP

#include "fpal.hpp"       // 引入定点数运算逻辑库
#include "hls_stream.h"   // HLS 数据流
#include "hls_burst_maxi.h" // HLS Burst AXI 接口 (用于纹理加载)

// 定义 Tile 尺寸和纹理尺寸常量
const int TILE_WIDTH = 32;
const int TILE_HEIGHT = 32;
const int TILE_PIXELS = TILE_WIDTH * TILE_HEIGHT;

const int TEX_WIDTH = 2048; // 纹理宽度，例如 2048x2048
const int TEX_HEIGHT = 2048; // 纹理高度
// 纹理数据现在是 24-bit RGB，所以一个 ap_uint<32> 可以存储一个纹素
// TEXTURE_RAM_SIZE_WORDS 表示缓存总大小，以 32 位字为单位
const int TEXTURE_RAM_SIZE_WORDS = 2048; // 纹理缓存总大小，8KB
const int TEX_CACHE_BURST_LEN = 16;      // 每次突发读取16个纹素（64字节）

// 计算纹理缓存行数
const int TEXTURE_CACHE_LINES = TEXTURE_RAM_SIZE_WORDS / TEX_CACHE_BURST_LEN; // 2048 / 16 = 128 行

// 纹理缓存行定义
struct TextureCacheLine {
    bool valid_bit;
    // 标签大小：(TEX_WIDTH * TEX_HEIGHT) 是总纹素数。
    // (TEX_WIDTH * TEX_HEIGHT) / TEX_CACHE_BURST_LEN 是总块数。
    // 2048 * 2048 = 4194304 纹素。
    // 4194304 / 16 = 262144 块。
    // log2(262144) = 18。所以需要 18 bits。
    ap_uint<18> tag; // 标签大小需要根据纹理块的逻辑地址范围确定，修正为18位
    // 纹理数据现在是 24-bit RGB，但存储在 ap_uint<32> 中，兼容 M_AXI 32位总线。
    ap_uint<32> data[TEX_CACHE_BURST_LEN]; // 16个纹素数据 (每个 32 位)
};


// PS 配置参数结构体 (通过 AXI-Lite 传递)
struct OppeConfig {
    fpal::vec3_fp_vec_unit light_dir;      // 光源方向向量
    fpal::vec3_fp_color_channel light_color;  // 光源颜色
    fpal::vec3_fp_color_channel ambient_color; // 环境光颜色

    ap_uint<16> tile_start_x;
    ap_uint<16> tile_start_y;
};

// 来自光栅化器的像素片段数据结构
struct PixelFragment {
    ap_uint<16> screen_x;        // 屏幕绝对 X 坐标
    ap_uint<16> screen_y;        // 屏幕绝对 Y 坐标
    fpal::fp_z_buffer_t interpolated_z; // 插值后的深度值
    fpal::vec2_fp_vec_unit interpolated_uv; // 插值后的 UV 坐标
    fpal::vec3_fp_vec_unit interpolated_normal; // 插值后的法线向量
};

// 声明 oppc_internal 命名空间及其内部全局变量
namespace oppc_internal {
    // 声明辅助函数
    void initialize_tile_buffers(fpal::fp_z_buffer_t z_buf[TILE_PIXELS], ap_uint<24> fb_buf[TILE_PIXELS], const int num_pixels);
    void initialize_texture_cache(TextureCacheLine cache[TEXTURE_CACHE_LINES], const int cache_size);

    void load_texture_block(TextureCacheLine cache[TEXTURE_CACHE_LINES], ap_uint<32>* texture_axi, ap_uint<18> block_addr, ap_uint<7> cache_line_idx); // 修正位宽
    ap_uint<7> get_cache_line_idx(ap_uint<18> block_addr); // 调整参数位宽
    // 点采样版本，返回 32 位纹素值 (通常高 8 位是 Alpha，这里只用 RGB 24位)
    ap_uint<32> get_texel_value_point_sample(TextureCacheLine cache[TEXTURE_CACHE_LINES], ap_uint<32>* texture_axi, ap_uint<16> u, ap_uint<16> v);

    // 点采样纹理采样函数，返回 24 位 RGB 颜色
    ap_uint<24> sample_texture_point_sample(TextureCacheLine cache[TEXTURE_CACHE_LINES], ap_uint<32>* texture_axi, fpal::fp_vec_unit_t uv_u, fpal::fp_vec_unit_t uv_v);

    ap_uint<24> calculate_blinn_phong(const OppeConfig& config, const fpal::vec3_fp_vec_unit& interpolated_normal, const ap_uint<24> texel_color_24bit);

    // 处理单个像素片段的具名函数
    void process_single_pixel(
        const PixelFragment& fragment,
        const OppeConfig& config,
        ap_uint<32>* texture_axi,
        ap_uint<24> frame_buffer_bram[TILE_PIXELS],
        fpal::fp_z_buffer_t z_buffer_bram[TILE_PIXELS],
        TextureCacheLine texture_cache_bram[TEXTURE_CACHE_LINES] // 传入内部静态缓存
    );

    // DATAFLOW 区域的生产者函数
    void read_fragments_producer(
        hls::stream<PixelFragment>& fragment_stream,
        hls::stream<PixelFragment>& valid_fragment_stream
    );

    // DATAFLOW 区域的消费者函数
    void process_pixels_consumer(
        hls::stream<PixelFragment>& valid_fragment_stream,
        const OppeConfig& config,
        ap_uint<32>* texture_axi,
        ap_uint<24> frame_buffer_bram[TILE_PIXELS],
        fpal::fp_z_buffer_t z_buffer_bram[TILE_PIXELS],
        TextureCacheLine texture_cache_bram[TEXTURE_CACHE_LINES] // 传入内部静态缓存
    );

} // namespace oppc_internal

// 移除以下行：
// const fpal::fp_vec_unit_t ONE_OVER_255_FP_VEC = (fpal::fp_vec_unit_t)(1.0f / 255.0f);

// OPPC 模块的顶层函数声明
void oppc_core(
    hls::stream<PixelFragment>& fragment_stream,
    const OppeConfig& config,
    ap_uint<32>* texture_axi, // M_AXI 纹理数据接口
    ap_uint<24> frame_buffer_bram[TILE_PIXELS], // 片上Framebuffer BRAM (作为输入/输出BRAM)
    fpal::fp_z_buffer_t z_buffer_bram[TILE_PIXELS], // 片上Z-Buffer BRAM (作为输入/输出BRAM)
    hls::stream<bool>& tile_processed_signal // 信号流，指示Tile处理完成
);

#endif // OPPC_HPP
